/**
 * Common function
 */
package com.lt.flashcard;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.bson.types.ObjectId;
import org.zkoss.bind.BindUtils;
import org.zkoss.image.AImage;
import org.zkoss.util.resource.Labels;
import org.zkoss.xel.fn.CommonFns;
import org.zkoss.xel.fn.StringFns;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.WebApps;
import org.zkoss.zk.ui.impl.PageImpl;
import org.zkoss.zk.ui.util.Configuration;

import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.entity.Notification;
import com.lt.flashcard.model.entity.Orderdetail;
import com.lt.flashcard.model.entity.Role;
import com.lt.flashcard.model.entity.User;
import com.lt.flashcard.model.service.AAService;
import com.lt.flashcard.model.service.Repository;
import com.lt.flashcard.model.service.UserService;
import com.mongodb.gridfs.GridFSDBFile;

/**
 * @author ocsen
 * 
 */
public class Utility {

    private static final Logger log = Logger.getLogger(Utility.class);

    public static final String DEF_AVATAR = "images/defavatar.png";
    public static final String DEF_FLASHCARDSET = "images/def_fcs.png";

    /**
     * Load image binary with id
     * @param image
     * @return
     * @throws java.io.IOException
     */
    public static AImage loadImageFromGridFS(String imageId) throws IOException {
        if (StringUtils.isBlank(imageId)) {
            return new AImage(Utility.getWebAppPath() + "/images/spacer.gif");
        }

        GridFSDBFile out = Repository.getInstance().findBinaryData(imageId);

        if (log.isInfoEnabled()) {
            log.info("Load image from old style: " + imageId);
        }

        if (out != null) {

            String path = Utility.getWebAppPath() + "/" + Utility.getConfiguration("com.lt.flashcard.imagecache", "") + "/" + imageId;
            File f = new File(path);
            if (!f.exists()) {
                FileOutputStream of = new FileOutputStream(f);
                out.writeTo(of);
                of.close();
            }

            return new AImage(path);
        } else {
            return new AImage(Utility.getWebAppPath() + "/images/spacer.gif");
        }
    }

    /**
     * Load image from gridfs and caching
     * @param imageId
     * @param defimage
     * @return
     */
    public static String loadImageFromGridFS(String imageId, String defimage) {
        if (Utility.isEmptyString(imageId)) {
            return defimage;
        }

        boolean isDot = imageId.indexOf(".") > -1;
        if (isDot) {
            return Utility.getImageCache() + "/" + imageId;
        }

        GridFSDBFile out = Repository.getInstance().findBinaryData(imageId);
        if (out != null) {
            try {
                AImage a = new AImage("", out.getInputStream());
                String fpath = Utility.getImageCache() + "/" + imageId + "." + a.getFormat();
                String path = Utility.getWebAppPath() + "/" + fpath;
                File f = new File(path);
                if (!f.exists()) {
                    FileOutputStream of = new FileOutputStream(f);
                    out.writeTo(of);
                    of.close();

                    log.info("Create images for id: " + imageId);
                }
                return fpath;
            } catch (Exception e) {
                log.error("Error create image", e);
            }
        } else {
            log.info("Fail to create images for id: " + imageId);
        }
        return defimage;
    }

    /**
     * Save a file to storage
     * @param filepath
     * @return String
     */
    public static String saveImage(String filepath) {
        File f = new File(filepath);
        if (!f.exists()) {
            return null;
        }

        try {
            return saveImage(new FileInputStream(f));
        } catch (Exception e) {
            log.error("Can't save file " + filepath, e);
            return null;
        }
    }

    /**
     * Save a input stream to file
     * @param stream
     * @return String
     */
    public static String saveImage(InputStream stream) {
        String name = new ObjectId().toString();

        try {
            AImage a = new AImage("", stream);
            String fname = name + "." + a.getFormat();
            String fpath = Utility.getImageCache() + "/" + fname;
            String path = Utility.getWebAppPath() + "/" + fpath;
            File f = new File(path);

            if (!f.exists()) {
                FileOutputStream of = new FileOutputStream(f);

                InputStream s = a.getStreamData();

                byte[] buffer = new byte[1024];
                int len = s.read(buffer);
                while (len != -1) {
                    of.write(buffer, 0, len);
                    len = s.read(buffer);
                }
                of.close();
            }

            return fname;
        } catch (Exception e) {
            log.error("Can't save image to storage", e);
            return null;
        }
    }

    /**
     * Delete imageId
     * @param imageId
     */
    public static void deleteImage(String imageId) {
        String path = Utility.getWebAppPath() + "/" + Utility.getImageCache() + "/" + imageId;
        File a = new File(path);
        try {
            a.delete();
        } catch (Exception e) {
            log.error("Can't delete file " + path, e);
        }
    }

    /**
     * Copy to a new image and return the name
     * @param image
     * @return
     */
    public static String copyImage(String image) {
        String name = new ObjectId().toString();
        String path = Utility.getWebAppPath() + "/" + Utility.getImageCache() + "/" + image;
        try {
            AImage a = new AImage(path);
            String np = Utility.getWebAppPath() + "/" + Utility.getImageCache() + "/" + name + "." + a.getFormat();
            FileUtils.copyFile(new File(path), new File(np));

            return name + "." + a.getFormat();
        } catch (Exception e) {
            log.error("Can't copy image " + image, e);
            return null;
        }
    }

    /**
     * Load data from file to byte array
     * @param filePath
     * @return
     */
    public static byte[] loadDataFromFile(String filePath) {
        File file = new File(filePath);
        if (!file.isFile()) {
            return null;
        }
        try {
            int size = (int) file.length();
            byte[] buffer = new byte[size];
            FileInputStream in = new FileInputStream(file);
            in.read(buffer);
            in.close();
            return buffer;
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * Generate the link to share on facebook or twitter
     * @param object
     * @return
     */
    public static String generateShareLink(Object object) {
        if (object instanceof FlashcardSet) {
            FlashcardSet fcs = (FlashcardSet) object;
            Long id = fcs.getId();
            String name = fcs.getName();
            if (fcs.getAdmin() == FlashcardSet.ADMIN_BUY) {
                id = Utility.parseLong(fcs.getOriginalflashcardsetCache());
                return getFullUrl(generateUrl("store_detail", id, name));
            } else if (fcs.getAdmin() == FlashcardSet.ADMIN_YES) {
                return getFullUrl(generateUrl("store_detail", fcs.getId(), fcs.getName()));
            } else {
                return getFullUrl(generateUrl("flashcardset", id, name));
            }
        }
        return "";
    }

    /**
     * Generate the link of medal to share on facebook or twitter
     * @param object
     * @return
     */
    public static String generateShareMedalLink(String uname, String medal) {
        if (uname != null) {
            if (medal == "") {
                return getFullUrl(generateUrl("medal", uname, null));
            } else {
                return getFullUrl(generateUrl("medal_detail", medal, uname));
            }
        }
        return "";
    }

    /**
     * Generate URL to a page with specific param
     * @param page
     * @return
     */
    public static String generateUrl(String type, Object id, String params) {
        boolean rewrite = Utility.isUrlRewrite();
        if (type.equals("wordlist")) {
            return Executions.encodeURL(rewrite ? "/collection" : "/wordlist.zul");
        } else if (type.equals("flashcardset")) {
            if (rewrite) {
                params = TextUtil.removeAccent(params).toLowerCase();
                return Executions.encodeURL(String.format("/set/%d/%s", id, params));
            } else {
                params = (StringUtils.isBlank(params)) ? ("id=" + id) : ("id=" + id + "&" + params);
                return Executions.encodeURL("/wordlist_detail_main.zul?" + params);
            }
        } else if (type.equals("editflashcardset")) {
            params = (StringUtils.isBlank(params)) ? ("id=" + id) : ("id=" + id + "&" + params);
            return Executions.encodeURL("/flashcard.zul?task=edit&" + params);
        } else if (type.equals("test")) {
            params = (StringUtils.isBlank(params)) ? ("fcid=" + id) : ("fcid=" + id + "&" + params);
            return Executions.encodeURL("/test.zul?" + params);
        } else if (type.equals("adminuserdetail")) {
            params = (StringUtils.isBlank(params)) ? ("id=" + id) : ("id=" + id + "&" + params);
            return Executions.encodeURL("/admin_user_detail.zul?" + params);
        } else if (type.equals("profile")) {
            if (id == null) {
                User u = Utility.getUser();
                if (u != null) {
                    id = u.getUsername();
                }
            }
            if (id instanceof Long) {
                String uid = "id=" + id;
                params = (StringUtils.isBlank(params)) ? uid : (uid + "&" + params);
                if (log.isInfoEnabled()) {
                    log.info("Generate url for old profile: " + uid);
                }
                return Executions.encodeURL("/profile.zul?" + params);
            } else {
                if (rewrite) {
                    return Executions.encodeURL(Utility.isEmptyString(params) ? String.format("/u/%s/profile", id) : String.format(
                            "/u/%s/profile?%s", id, params));
                } else {
                    String uid = "uname=" + id;
                    params = (StringUtils.isBlank(params)) ? uid : (uid + "&" + params);
                    return Executions.encodeURL("/profile.zul?" + params);
                }
            }
        } else if (type.equals("dashboard")) {
            if (id == null) {
                User u = Utility.getUser();
                if (u != null) {
                    id = u.getUsername();
                }
            }
            if (id instanceof Long) {
                String uid = "uid=" + id;
                params = (StringUtils.isBlank(params)) ? uid : (uid + "&" + params);
                if (log.isInfoEnabled()) {
                    log.info("Generate url for old dashboard: " + uid);
                }
                return Executions.encodeURL("/dashboard.zul?" + params);
            } else {
                if (rewrite) {
                    return Executions.encodeURL(Utility.isEmptyString(params) ? String.format("/u/%s", id) : String.format("/u/%s?%s", id,
                            params));
                } else {
                    String uid = "uname=" + id;
                    params = (StringUtils.isBlank(params)) ? uid : (uid + "&" + params);
                    return Executions.encodeURL("/dashboard.zul?" + params);
                }
            }
        } else if (type.equals("profile_journey")) {
            params = (StringUtils.isBlank(params)) ? ("id=" + id) : ("id=" + id + "&" + params);
            return Executions.encodeURL("/profile_journey.zul?" + params);
        } else if (type.equals("profile_medal")) {
            if (id == null) {
                User u = Utility.getUser();
                if (u != null) {
                    id = u.getUsername();
                }
            }
            if (id instanceof Long) {
                String uid = "id=" + id;
                params = (StringUtils.isBlank(params)) ? uid : (uid + "&" + params);
                return Executions.encodeURL("/profile_medal.zul?" + params);
            } else {
                if (rewrite) {
                    return Executions.encodeURL(Utility.isEmptyString(params) ? String.format("/u/%s/medal", id) : String.format(
                            "/u/%s/medal?%s", id, params));
                } else {
                    String uid = "uname=" + id;
                    params = (StringUtils.isBlank(params)) ? uid : (uid + "&" + params);
                    return Executions.encodeURL("/profile_medal.zul?" + params);
                }
            }
        } else if (type.equals("medal_detail")) {
            return Executions.encodeURL(String.format("/u/%s/medal/%s", params, id));
        } else if (type.equals("profile_friend")) {
            params = (StringUtils.isBlank(params)) ? ("id=" + id) : ("id=" + id + "&" + params);
            return Executions.encodeURL("/profile_friendlist.zul?" + params);
        } else if (type.equals("store")) {
            params = (StringUtils.isBlank(params)) ? "" : params;
            if (params.length() > 0) {
                params = (rewrite ? "/" : "?cat=").concat(params);
            }
            return Executions.encodeURL((rewrite ? "/store" : "/store.zul") + params);
        } else if (type.equals("store_overview")) {
            params = (StringUtils.isBlank(params)) ? "" : params;
            if (params.length() > 0) {
                params = "?".concat(params);
            }
            return Executions.encodeURL((rewrite ? "/store" : "/store_overview.zul") + params);
        } else if (type.equals("getblankflashcard")) {
            return Executions.encodeURL("/store/flashcard-trang");
        } else if (type.equals("admin_flashcardset_details")) {
            params = (StringUtils.isBlank(params)) ? ("fcsid=" + id) : ("fcsid=" + id + "&" + params);
            return Executions.encodeURL("admin_flashcardset_details.zul?" + params);
        } else if (type.equals("store_detail")) {
            if (rewrite) {
                params = TextUtil.removeAccent(params).toLowerCase();
                return Executions.encodeURL(String.format("/store/%s/%s", id, params));
            } else {
                params = (StringUtils.isBlank(params)) ? ("id=" + id) : ("id=" + id + "&" + params);
                return Executions.encodeURL("store_detail.zul?" + params);
            }
        } else if (type.equals("learn")) {
            params = (StringUtils.isBlank(params)) ? ("id=" + id) : ("id=" + id + "&" + params);
            return Executions.encodeURL("learn.zul?" + params);
        } else if (type.equals("category")) {
            params = (StringUtils.isBlank(params)) ? ("cat=" + id) : ("id=" + id + "&" + params);
            return Executions.encodeURL("wordlist.zul?" + params);
        } else if (type.equals("resetpassword")) {
            params = (StringUtils.isBlank(params)) ? ("code=" + id) : ("code=" + id + "&" + params);
            return Executions.encodeURL("resetpassword.zul?" + params);
        } else if (type.equals("order")) {
            return Executions.encodeURL("/order");
        } else {
            return Executions.encodeURL(type);
        }
    }

    /**
     * Generate page title
     * @param type
     * @param param
     * @return
     */
    public static String generateTitle(String type, Object param) {
        String ret = "";
        if (type.equals("flashcardset")) {
            FlashcardSet set = (FlashcardSet) param;
            ret = set.getName();
        }
        return ret.length() > 0 ? ret.concat(" | Flashcard Blueup") : "Flashcard Blueup – Learn and Share your knowledge";
    }

    /**
     * Generate page description
     * @param type
     * @param param
     * @return
     */
    public static String generateDescription(String type, Object param) {
        String ret = "";
        if (type.equals("flashcardset")) {
            FlashcardSet set = (FlashcardSet) param;
            ret = Utility.isEmptyString(set.getDescription()) ? "Học tập bằng flashcard giúp tăng 90% hiệu quả và trải nghiệm sự thú vị"
                    : set.getDescription();
        }
        return ret;
    }

    /**
     * Format the date with pattern
     * @param date
     * @param pattern
     * @return
     */
    public static String formatDate(Date date, String pattern) {
        if (date == null) {
            return "";
        }
        return CommonFns.formatDate(date, pattern);
    }

    /**
     * Format the date with default format
     * @param date
     * @return
     */
    public static String formatDate(Date date) {
        return formatDate(date, Labels.getLabel("date_format"));
    }

    /**
     * Format a number as string
     * @param value
     * @param format
     * @return
     */
    public static String formatNumber(Object value, String format) {
        return CommonFns.formatNumber(value, format);
    }

    /**
     * 
     * @param value
     * @param format
     * @return
     */
    public static String formatPrice(int value) {
        if (value == 0) {
            return "Miễn phí";
        }
        return CommonFns.formatNumber(value, "###,###đ");
    }

    /**
     * Return current subject
     * @return
     */
    public static Subject getSubject() {
        return Repository.getInstance().getAAService().getCurrentSubject();
    }

    /**
     * Return current user
     * @return
     */
    public static User getUser() {
        return Repository.getInstance().getAAService().getCurrentUser();
    }

    /**
     * Specify current user has specific role
     * @param role
     * @return
     */
    public static boolean hasRole(String role) {
        return Repository.getInstance().getAAService().hasRole(role);
    }

    /**
     * Check to see if current user has permission
     * @param permission
     * @return
     */
    public static boolean hasPermission(String permission) {
        return Repository.getInstance().getAAService().hasPermission(permission);
    }

    /**
     * Check to see if current subject is authenticated (login)
     * @return
     */
    public static boolean isLogin() {
        return Repository.getInstance().getAAService().isLogin();
    }

    public static boolean isEmptyString(String s) {
        return StringUtils.isBlank(s);
    }

    public static String getWebAppPath() {
        String path = Executions.getCurrent().getDesktop().getWebApp().getRealPath("/");
        return path;
    }

    /**
     * Get full url to webserver
     * @return
     */
    public static String getServerUrl() {
        return Utility.getConfiguration("com.lt.flashcard.serverurl", "");
    }

    /**
     * Get image cache folder
     * @return
     */
    public static String getImageCache() {
        return Utility.getConfiguration("com.lt.flashcard.imagecache", "");
    }

    public static String getIp() {
        return Executions.getCurrent().getRemoteAddr();
    }

    /**
     * Parse an array of string to Long number
     * @param data
     * @return
     */
    public static Long[] parseLong(String[] data) {
        if (data == null || data.length == 0) {
            return new Long[0];
        }

        int valid = 0;
        Long[] result = new Long[data.length];
        for (String string : data) {
            try {
                Long l = Long.parseLong(string);
                result[valid] = l;
                valid++;
            } catch (Exception e) {
            }
        }

        return Arrays.copyOf(result, valid);
    }

    /**
     * Try to parse a Long string
     * @param data
     * @return
     */
    public static Long parseLong(String data) {
        try {
            return Long.parseLong(data);
        } catch (Exception e) {
            return (long) 0;
        }
    }

    /**
     * Try to parse int string
     * @param data
     * @return
     */
    public static int parseInt(String data) {
        try {
            return Integer.parseInt(data);
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * Do redirect to raw target
     * @param target
     */
    public static void rawRedirect(String target, boolean isAu) {
        try {
            Execution exec = Executions.getCurrent();
            if (isAu) {
                exec.sendRedirect(target);
            } else {
                HttpServletResponse response = (HttpServletResponse) exec.getNativeResponse();
                response.sendRedirect(target);
                exec.setVoided(true);
            }
        } catch (IOException e) {
        }
    }

    /**
     * Get context path of current app
     * @return
     */
    public static String getContextPath() {
        return Executions.getCurrent().getContextPath();
    }

    /**
     * Remove the context path from full url and return relative url
     * @param fullurl
     * @return
     */
    public static String removeContextPath(String fullurl) {
        Execution exec = Executions.getCurrent();
        return fullurl.replaceFirst(exec.getContextPath(), "");
    }

    public static String getFullUrl(String url) {
        return getServerUrl().concat(removeContextPath(url));
    }

    /**
     * Redirect to a specific page
     * @param target
     */
    public static void redirect(String target, boolean isAu) {
        try {
            Execution exec = Executions.getCurrent();
            rememberCurrentPage();
            if (isAu) {
                Executions.sendRedirect(target);
            } else {
                HttpServletResponse response = (HttpServletResponse) exec.getNativeResponse();
                response.sendRedirect(exec.encodeURL(target));
                exec.setVoided(true);
            }
        } catch (IOException e) {
        }
    }

    /**
     * Redirect to login page or access denied
     * @param target
     */
    public static void loginOrAccessDenied(boolean isAu) {
        if (isLogin()) {
            displayAccessDenied(isAu);
        } else {
            redirect("/login.zul", isAu);
        }
    }

    /**
     * Redirect to login page in case not authenticated
     * @param isAu
     */
    public static void requireAuthenticated(boolean isAu) {
        if (!isLogin()) {
            redirect("/login.zul", isAu);
        }
    }

    /**
     * Require authenticated user and has role admin
     * @param isAu
     */
    public static void adminLoginOrAccessDenied(boolean isAu) {
        if (Utility.isLogin()) {
            AAService asrv = Repository.getInstance().getAAService();
            if (!asrv.hasRole(Role.ROLE_ADMIN)) {
                displayAccessDenied(isAu);
            }
        } else {
            redirect("/admin_login.zul", isAu);
        }
    }

    /**
     * Redirect to access denied page
     */
    public static void displayAccessDenied(boolean isAu) {
        redirect("/accessdenied.zul", isAu);
    }

    /**
     * Display 404 page
     * @param isAu
     */
    public static void display404(boolean isAu) {
        redirect("/404.zul", isAu);
    }

    /**
     * Get URL of current processing page
     * @return
     */
    public static String getCurrentPage() {
        Execution exec = Executions.getCurrent();
        HttpServletRequest request = (HttpServletRequest) exec.getNativeRequest();

        String queryUrl = request.getRequestURI();
        String queryString = request.getQueryString();

        if (queryString != null) {
            queryUrl = queryUrl.concat("?").concat(queryString);
        }
        return queryUrl;
    }

    /**
     * Remember current page
     */
    public static void rememberCurrentPage() {
        Execution exec = Executions.getCurrent();
        HttpServletRequest request = (HttpServletRequest) exec.getNativeRequest();

        String contextPath = request.getContextPath();
        String queryUrl = request.getRequestURI();
        String queryString = request.getQueryString();

        queryUrl = queryUrl.replaceFirst(contextPath, "");
        if (queryString != null) {
            queryUrl = queryUrl.concat("?").concat(queryString);
        }

        if (queryUrl.indexOf("logout.zul") > -1 || queryUrl.indexOf("admin_logout.zul") > -1) {
            return;
        }

        Session ses = Utility.getSubject().getSession();
        try {
            ses.setAttribute("previousUrl", queryUrl);
        } catch (Exception e) {
        }
    }

    /**
     * Remember page to redirect
     * @param page
     */
    public static void rememberPage(String page) {
        Session ses = Utility.getSubject().getSession();
        ses.setAttribute("previousUrl", page);
    }

    /**
     * Redirect to previous page
     */
    public static void gotoPreviousPage(boolean isAu) {
        String url = getRememberPage();
        if (url != null) {
            clearRememberPage();
            rawRedirect(url, isAu);
        }
    }

    /**
     * Get rememberpage
     * @return
     */
    public static String getRememberPage() {
        Session ses = Utility.getSubject().getSession();
        return (String) ses.getAttribute("previousUrl");
    }

    public static void clearRememberPage() {
        Session ses = Utility.getSubject().getSession();
        ses.setAttribute("previousUrl", null);
    }

    public static String getConfiguration(String name, String defaultValue) {
        Configuration conf = WebApps.getCurrent().getConfiguration();
        return conf.getPreference(name, defaultValue);
    }

    public static int getConfigurationInt(String name, String defaultValue) {
        return Integer.parseInt(getConfiguration(name, defaultValue));
    }

    /**
     * Get streaming folder for audio
     * @return
     */
    public static String getStreamFolder() {
        return String.valueOf(getConfiguration("com.lt.flashcard.audioStreamFolder", ""));
    }

    /**
     * Random the order in the list of object
     * @param sequence
     * @return
     */
    public static Object[] randomOrder(List<Object> sequence) {
        Object[] retArray = sequence.toArray();

        for (int i = 0; i < retArray.length - 1; i += 1) {
            int swapIndex = i + (int) (Math.random() * (retArray.length - i));
            Object temp = retArray[i];
            retArray[i] = retArray[swapIndex];
            retArray[swapIndex] = temp;
        }

        return retArray;
    }

    /**
     * check permission: edit, delete flashcard(s)
     */
    public static boolean checkPermision(FlashcardSet flashcardset) {
        if (isLogin()) {
            if (!flashcardset.getAuthor().getId().equals(getUser().getId())) {
                return false;
            }
        } else {
            return false;
        }
        return true;
    }

    /**
     * getRank
     */
    public static int getRank(User user) {
        UserService srv = Repository.getInstance().getUserService();
        return srv.getRank(user);
    }

    /**
     * getFriendRank
     */
    public static int getFriendRank(User user, User currUser) {
        UserService srv = Repository.getInstance().getUserService();
        return srv.getFriendRank(user, currUser);
    }

    /**
     * render time
     */
    private static String renderTime(Date time) {
        String text = "";
        Date currTime = new Date();

        Long ltime = currTime.getTime() - time.getTime();

        int ONE_YEAR = 365 * 24 * 60 * 60 * 1000;
        int ONE_MONTH = 30 * 24 * 60 * 60 * 1000;// 1MOTH = 30 DAYS
        int ONE_DAY = 24 * 60 * 60 * 1000;
        int ONE_HOUR = 60 * 60 * 1000;

        int year = (int) (ltime / ONE_YEAR);
        int month = (int) (((ltime % ONE_YEAR) * ONE_YEAR) / ONE_MONTH);
        month = (month > 0 ? month : 0);
        int date = (int) ((ltime - (year * ONE_YEAR + month * ONE_MONTH)) / ONE_DAY);
        date = date > 0 ? date : 0;
        int hour = (int) ((ltime - (year * ONE_YEAR + month * ONE_MONTH + date * ONE_DAY)) / ONE_HOUR);
        hour = hour > 0 ? hour : 0;
        int minute = (int) ((ltime - (year * ONE_YEAR + month * ONE_MONTH + date * ONE_DAY + hour * ONE_HOUR)) / (60 * 1000));
        minute = minute > 0 ? minute : 0;
        int sec = (int) (ltime / 1000);

        if (year > 0 && month > 0) {
            return text += "kho?ng " + year + " nam " + month + " tru?c.";
        }
        if (year > 0 && month == 0) {
            return text += year + " nam tru?c.";
        }

        if (month > 0 && date > 15) {
            return text += "g�`n " + (month + 1) + "th�ng tru?c.";
        }
        if (month > 0 && date < 15) {
            return text += "hon " + month + "th�ng tru?c.";
        }

        if (date > 0 && hour > 12) {
            return text += "g�`n " + (date + 1) + " ng�y tru?c.";
        }
        if (date > 0 && hour < 12) {
            return text += "hon " + date + " ng�y tru?c.";
        }

        if (hour > 0 && minute > 0) {
            return text += "kho?ng " + hour + " gi? " + minute + " phu�t tru?c.";
        }
        if (hour > 0 && minute == 0) {
            return text += "kho?ng " + hour + " gio` tru?c.";
        }
        if (minute > 50) {
            return text += "kho?ng 1 gio` tru?c.";
        }

        if (minute > 0 && sec == 0) {
            return text += "kho?ng " + minute + " ph�t tru?c.";
        }
        if (minute > 0 && sec == 0) {
            return text += minute + " ph�t tru?c.";
        }
        if (sec > 50 && sec < 60) {
            return text += "kho?ng 1 ph�t tru?c.";
        }
        if (sec > 3) {
            return text += sec + " gi�y.";
        } else {
            return text = "v�i gi�y tru?c";
        }
    }

    public static String renderTime2Text(Date time, String type) {
        String htmlTime = "";
        String textTime = renderTime(time);

        // d�? th�m link sau na`y
        if (type.equals("fcscomment")) {
            htmlTime = "<a href='javascript:;' title='" + formatDate(time, Labels.getLabel("date_format2")) + "' class='rendertime'>"
                    + textTime + "</a>";
        }
        if (type.equals("notification")) {
            htmlTime = "<a href='javascript:;' title='" + formatDate(time, Labels.getLabel("date_format2")) + "' class='rendertime'>"
                    + textTime + "</a>";
        }
        return htmlTime;
    }

    /**
     * render notification
     */
    public static String renderNofitication(Notification notify) {
        String text = "";
        switch (notify.getType()) {
        case Notification.TYPE_COMMENT:
            text = "<a href='" + Utility.generateUrl("dashboard", notify.getSourceuid(), null) + "' id='source'> "
                    + notify.getSourceuname() + " </a>" + "<span> " + Labels.getLabel("notification.comment") + " </span>" + "<a href='"
                    + Utility.generateUrl("dashboard", notify.getRelatedid(), null) + "' id='target'> " + notify.getRelatedname() + " </a>"
                    + "<span> " + Labels.getLabel("notification.your") + " </span>";
            break;
        case Notification.TYPE_REPLYCOMMENT:
            text = "<a href='" + Utility.generateUrl("dashboard", notify.getSourceuid(), null) + "' id='source'> "
                    + notify.getSourceuname() + " </a> " + "<span> " + Labels.getLabel("notification.replycomment") + " </span>"
                    + "<a href='" + Utility.generateUrl("dashboard", notify.getRelatedid(), null) + "' id='target'> "
                    + notify.getRelatedname() + " </a> ";
            break;
        case Notification.TYPE_FRIENDREQUEST:
            text = "<a href='" + Utility.generateUrl("dashboard", notify.getSourceuid(), null) + "' id='source'> "
                    + notify.getSourceuname() + " </a>" + "<span> " + Labels.getLabel("notification.friendrequest") + " </span>";
            break;
        case Notification.TYPE_ACCEPTEDFRIENDREQUEST:
            text = "<span>" + Labels.getLabel("notification.friendrequest1") + "</span>" + "<a href='"
                    + Utility.generateUrl("dashboard", notify.getSourceuid(), null) + "' id='source'> " + notify.getSourceuname() + " </a>"
                    + "<span> " + Labels.getLabel("notification.friendrequest2") + " </span>";
            break;
        case Notification.TYPE_PRIVATEMSG:
            text = "<span> " + Labels.getLabel("notification.acceptedfriendrequest") + " </span>" + "<a href='"
                    + Utility.generateUrl("dashboard", notify.getSourceuid(), null) + "' id='source'> " + notify.getSourceuname()
                    + ". </a>";
            break;
        case Notification.TYPE_RATING:
            text = "<a href='" + Utility.generateUrl("dashboard", notify.getSourceuid(), null) + "' id='source'> "
                    + notify.getSourceuname() + " </a>" + "<span> " + Labels.getLabel("notification.rating") + " </span>" + "<a href='"
                    + Utility.generateUrl("flashcardset", notify.getRelatedid(), null) + "' id='target'> " + notify.getRelatedname()
                    + " </a>" + "<span> " + Labels.getLabel("notification.your") + ": " + notify.getData() + " sao. </span>";
            break;
        case Notification.TYPE_SHARE:
            text = "<a href='" + Utility.generateUrl("dashboard", notify.getSourceuid(), null) + "' id='source'> "
                    + notify.getSourceuname() + " </a>" + "<span> " + Labels.getLabel("notification.share") + " </span>" + "<a href='"
                    + Utility.generateUrl("flashcardset", notify.getRelatedid(), null) + "' id='target'> " + notify.getRelatedname()
                    + " </a>" + "<span> " + Labels.getLabel("notification.your") + ".</span>";
            break;
        case Notification.TYPE_SYSTEM:
            text = "<span>system nhi�`u qua� chua bi�t co� ca�i na`o. tu` tu` la`m...:D.</span>";
            break;
        default:
            break;
        }
        return text;
    }

    /**
     * isFriendRequest
     */
    public static boolean isFriendRequest(int type, int status) {
        if (type == Notification.TYPE_FRIENDREQUEST && status != Notification.STATUS_ACCEPTEDFRIENDREQUEST) {
            return true;
        }
        return false;
    }

    /**
     * is currentuser
     * 
     * @param uid
     *            : user id
     * @return {@link Boolean}
     */
    public static boolean isCurrentUser(Long uid) {
        if (uid.equals(getUser().getId())) {
            return true;
        }
        return false;
    }

    /**
     * Check to see if the url rewrite is enabled
     * @return
     */
    public static boolean isUrlRewrite() {
        int rs = getConfigurationInt("com.lt.flashcard.urlrewrite", "0");
        return rs == 1;
    }

    /**
     * substring: message
     * 
     * @param message
     * @return {@link String}
     */
    public static String strTruncate(String message, int length, boolean hasDot) {

        if (hasDot) {
            if (message.length() > length - 4) {
                message = message.substring(0, length - 4);
                message += " ...";
            }
        } else {
            if (message.length() < length) {
                length = message.length();
            }
            message = message.substring(0, length);
        }
        return message;
    }

    /**
     * Do submit data via POST and get return data
     * @param url
     * @param data
     * @return
     */
    public static String wrapContentViaPOST(String fullurl, Map<String, String> data) {
        try {

            if (log.isInfoEnabled()) {
                log.info(String.format("Grap via POST url: %s param: %s", fullurl, data.toString()));
            }

            List<String> param = new ArrayList<String>();
            if (data != null) {
                for (Entry<String, String> i : data.entrySet()) {
                    param.add(String.format("%s=%s", i.getKey(), i.getValue()));
                }
            }
            String p = StringFns.join(param.toArray(), "&");

            URL url = new URL(fullurl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setInstanceFollowRedirects(false);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestProperty("charset", "utf-8");
            connection.setRequestProperty("Content-Length", String.valueOf(p.length()));
            connection.setUseCaches(false);

            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.writeBytes(p);
            wr.flush();

            BufferedReader buffer = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF8"));
            StringBuilder builder = new StringBuilder();

            int byteRead;
            while ((byteRead = buffer.read()) != -1) {
                builder.append((char) byteRead);
            }
            buffer.close();

            if (log.isInfoEnabled()) {
                log.info(String.format("Result: %s", builder.toString()));
            }

            return builder.toString();
        } catch (Exception e) {
            return "";
        }
    }

    public static String wrapContentviaGET(String fullurl) {
        try {
            URL url = new URL(fullurl);
            URLConnection urlc = url.openConnection();
            BufferedReader buffer = new BufferedReader(new InputStreamReader(urlc.getInputStream(), "UTF8"));
            StringBuilder builder = new StringBuilder();

            int byteRead;
            while ((byteRead = buffer.read()) != -1) {
                builder.append((char) byteRead);
            }
            buffer.close();
            return builder.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    public static void test(Orderdetail order) {

    }

    public static String checkNull(String str) {
        if ((str == null) || str.isEmpty()) {
            return "";
        }
        return str;
    }

    /**
     * Generate url to open share facebook dialog
     * @param target
     * @return
     */
    public static String shareFacebook(String target) {
        return "https://www.facebook.com/dialog/feed?app_id=" + getConfiguration("com.lt.flashcard.facebook_appid", "") + "&link=" + target
                + "&redirect_uri=" + Utility.getConfiguration("com.lt.flashcard.serverurl", "http://blueup.vn");
    }

    /**
     * Generate url to share via twitter
     * @param target
     * @return
     */
    public static String shareTwitter(String target) {
        return "https://twitter.com/share?url=" + target;
    }

    /**
     * Generate url to share via google plus
     * @param target
     */
    public static String shareGPlus(String target) {
        return "https://plus.google.com/share?url=" + target;
    }

    /**
     * Add an amount of blue coin to status bar
     * @param amount
     */
    public static void addBlueCoin(int amount) {
        if (amount == 0) {
            return;
        }
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("coin", amount);
        BindUtils.postGlobalCommand(null, null, "updateBlueCoin", param);
    }

    public static void addOgTag(Page page, String title, String description, String image) {
        PageImpl rpage = (PageImpl) page;
        rpage.setTitle(title);
        if (!isEmptyString(image)) {
            image = getServerUrl() + "/" + image;
        }
        rpage.addBeforeHeadTags(String.format("<base href='%s/' >", getContextPath()));
        rpage.addBeforeHeadTags(String.format("<meta name=\"%s\" content=\"%s\" />", "description", description));
        rpage.addBeforeHeadTags(String.format("<meta property=\"%s\" content=\"%s\" />", "og:title", title));
        rpage.addBeforeHeadTags(String.format("<meta property=\"%s\" content=\"%s\" />", "og:description", description));
        rpage.addBeforeHeadTags(String.format("<meta property=\"%s\" content=\"%s\" />", "og:image", image));
        rpage.addBeforeHeadTags(String.format("<meta property=\"%s\" content=\"%s\" />", "og:site_name", "Flashcard Blueup"));
    }

    /**
     * Filter valid emails from a collection
     * @param emails
     * @return
     */
    public static Set<String> filterValidEmails(Collection<String> emails) {
        Set<String> ret = new HashSet<String>();
        Iterator<String> it = emails.iterator();
        while (it.hasNext()) {
            String e = it.next();
            e = e.trim();
            if (e.matches(".+@.+.[a-z]+")) {
                ret.add(e);
            }
        }
        return ret;
    }
}